<?php
/**
 * 怎么支持多数据源的操作，比方说多个数据库，
 * 通过不同的adapter来区别
 * 
 * 支持ORM，这个abstractTable其实维护了一个实体的数据库table到PfinalPluginORMKit的映射关系
 * <table,entity>，每个entity支持set方法
 * @author huangyusheng
 * @since 2014-3-7
 * @package project_name.package_name
 */
abstract class PfinalModelAbstract {
	// TODO - Insert your code here
	/**
	 * 
	 * @var Pfinal_Plugin_ActiveRecord
	 */
	protected $activeRecord;
	
	protected $adapter;
	/**
	 * 
	 * @var Pfinal_Plugin_DbConnection
	 */
	protected $connection;
	
	protected $schema = array();
	
	protected $databaseName;
	
	protected $tableName;
	
	protected $primaryId;
	
	protected $modifiedSet = array();

	protected $conditions = array();
		
	const DEFINITION_PRIMARY_KEY = 'PRI';
	
	protected $selectorChain;
	
	protected $isOrmEnable = false;
	
	protected $cacheManager;	
	
	/**
	 * 初始化activeRecord插件
	 * @throws Pfinal_Exception_Runtime
	 */
	public function __construct($ormEnable = true){
		$this->activeRecord = Pfinal::isRegistedPlugin(new Pfinal_Plugin_ActiveRecord());
		if (null===$this->activeRecord) {
			throw new Pfinal_Exception_Runtime("active record plugin is not added");
		}
		try{
			$this->isOrmEnable = Pfinal::getKernelConfig()->getConstant()->getOrmEnable();
			if ($this->isOrmEnable){
				$this->isOrmEnable = $ormEnable;
			}
			//初始化adapter信息
			$this->connection = $this->activeRecord->getDataSource($this->databaseName);
			$this->cacheManager = Pfinal_Plugin_Cache_Kit::getByName('memcache');
			$this->getMetaData();
			//do some cache
		}catch(Exception $ex){
			//var_dump($ex);
			throw new Pfinal_Exception_Runtime($ex->getMessage(),$ex->getCode());
		}
	}
	
	protected function initAdapter(Pfinal_Model_Statement $stm){
		$this->adapter = $this->connection->getAdapter($stm);
	}
	
	protected function getMetaData(){
		if (empty($this->schema)){			
			if (!empty($this->databaseName)){
				if (null!==$this->cacheManager){
					$this->schema = $this->cacheManager->get($this->databaseName.$this->tableName);
				}
				if (!$this->schema){
					$ddl = new Pfinal_Model_DDL();
					$this->initAdapter($ddl);
					$ddl->desc($this->tableName);
					$this->schema = $this->adapter->call($ddl);
					if ($this->cacheManager)
						$this->cacheManager->set($this->databaseName.$this->tableName,$this->schema,3600);
				}

			}
		}
		foreach ($this->schema as $definition){
			if ($definition['Key'] === self::DEFINITION_PRIMARY_KEY){
				$this->primaryId = $definition['Field'];
				break;
			}
		}
	}
	
	/**
	 * activerecord相关的方法
	 */
	public function findById($primaryId){
		$selector = new Pfinal_Model_Selector();
		$selector->from($this->tableName);
		//primaryId是数组，批量查询
		if (is_array($primaryId)){
			$selector->where($this->primaryId.'IN(?)', $primaryId);
		}elseif (is_scalar($primaryId)){
			$selector->where($this->primaryId.'=?', $primaryId);
		}
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($selector);
		//这里返回的是原始的dataset数据，根据是否启动orm来判断返回的数据类型
		if ($this->isOrmEnable){
			$data = $this->activeRecord->buildEntity($this->tableName,$dataset);
		}else{
			$data = $dataset;
		}
		return empty($data)?array():$data;
	}
	
	/**
	 * 
	 */
	public function fetchAll($conditions = array(),$orderBy = '',$offset = null,$count = null){
		$selector = new Pfinal_Model_Selector();
		$selector->from($this->tableName);
		if (!empty($conditions)) {
			foreach ($conditions as $key => $value) {
				$selector->where($key,$value);
			}
		}
		if (!empty($orderBy)) {
			//$selector->orderBy($orderBy);
		}
		if(!is_null($offset)&&!is_null($count))
			$selector->limit($count,$offset);
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($selector);
		if ($this->isOrmEnable){
			return $this->activeRecord->buildEntity($this->tableName,$dataset);
		}else{
			return $dataset;
		}
	}
	/**
	 * [fetchBySelector description]
	 * @param  Pfinal_Model_Selector $selector [description]
	 * @return [type]                          [description]
	 */
	public function fetchBySelector(Pfinal_Model_Selector $selector){
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($selector);
		if ($this->isOrmEnable){
			return $this->activeRecord->buildEntity($this->tableName,$dataset);
		}else{
			return $dataset;
		}
	}

	/**
	 * 
	 */
	public function fetchOne($conditions = array()){
		$selector = new Pfinal_Model_Selector();
		$selector->from($this->tableName);
		if (!empty($conditions)) {
			foreach ($conditions as $key => $value) {
				$selector->where($key,$value);
			}
		}
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($selector);
		if ($this->isOrmEnable){
			$ret = $this->activeRecord->buildEntity($this->tableName,$dataset);
		}else{
			$ret = $dataset;
		}
		return count($ret)>=1?$ret[0]:array();
	}
	
	public function from($from,$fields = '*',$condition = array()){
		$this->selectorChain = new Pfinal_Model_SelectorChain();
		$selector = $this->select();
		$selector->from($from,$fields);
		foreach ($condition as $key=>$value){
			$selector->where($key, $value);
		}
		$this->selectorChain->start($selector);
		return $this;
	}
	
	public function innerJoin($from,$on,$fields = '*',$condition = array()){
		$selector = $this->select();
		$selector->from($from,$fields);
		foreach ($condition as $key=>$value){
			$selector->where($key, $value);
		}
		$this->selectorChain->innerJoin($selector,$on);
		return $this;
	}
	
	public function orderBy($orderBy,$order){
		$this->selectorChain->orderBy($orderBy,$order);
		return $this;
	}
	
	public function limit($offset,$count){
		$this->selectorChain->limit($count,$offset);
		return $this;
	}

	/**
	 * [count description]
	 * @param  array  $conditions [description]
	 * @return [type]             [description]
	 */
	public function count($conditions = array()){
		$selector = new Pfinal_Model_Selector();
		$selector->from($this->tableName,'count(*) as total');
		if (!empty($conditions)) {
			foreach ($conditions as $key => $value) {
				$selector->where($key,$value);
			}
		}
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($selector);
		if (!empty($dataset)) {
			$ret = (int)$dataset[0]['total'];
		}else{
			$ret = 0;
		}
		return $ret;
	}

	/**
	 * [countBySelector description]
	 * @param  Pfinal_Model_Selector $selector [description]
	 * @return [type]                          [description]
	 */
	public function countBySelector(Pfinal_Model_Selector $selector){
		$s = clone $selector;
		$s->from($this->tableName,'count(*) as total');
		$this->initAdapter($selector);
		$dataset = $this->adapter->query($s);
		if (!empty($dataset)) {
			$ret = (int)$dataset[0]['total'];
		}else{
			$ret = 0;
		}
		return $ret;
	}

	
	/**
	 * 创建表结构
	 * @param unknown_type $schema
	 */
	public function create($schema){
		throw new Pfinal_Exception_Runtime("unimplemented exception!");
	}
	
	protected function set($field,$value){
		$this->modifiedSet[$field] = $value;
		return $this;
	}

	protected function where($k,$v){
		$this->conditions[$k] = $v;
		return $this;
	}
	
	public function query($complexTableName = null){
		return $this->doQuery($this->selectorChain,$complexTableName);
	}


	public function update(){
		$updator = new Pfinal_Model_Update();
		$updator->from($this->tableName)->setBatch($this->modifiedSet);
		if (!empty($this->conditions)) {
			foreach ($this->conditions as $key => $value) {
				$updator->where($key,$value);
			}
		}
		$this->initAdapter($updator);
		return $this->adapter->execute($updator);
	}

	
	/**
	 * 
	 */
	public function save(){
		$insert = new Pfinal_Model_Insert();
		$insert->from($this->tableName)->setBatch($this->modifiedSet);
		$this->initAdapter($$insert);
		return $this->adapter->insert($insert);
	}
	
	/**
	 * 
	 * @param Pfinal_Model_Adapter_Interface $adapter
	 * @return Pfinal_Model_Selector
	 */
	protected function select(){
		return new Pfinal_Model_Selector($this->adapter);
	}
	
	/**
	 * 
	 * @return Pfinal_Model_SelectorChain
	 */
	protected function beginQuery(){
		return new Pfinal_Model_SelectorChain();
	}
	
	/**
	 * 
	 * @param Pfinal_Model_SelectorChain $chain
	 * @param Pfinal_Model_Optimizer_Interface $optimizer
	 * @return [type]
	 */
	protected function doQuery(Pfinal_Model_SelectorChain $chain,$complexTableName = null,Pfinal_Model_Optimizer_Interface $optimizer = null){
		$client = new Pfinal_Model_QueryClient();
		$dataset = $client->doQuery($chain,$optimizer);
		if ($this->isOrmEnable){
			$ret = $this->activeRecord->buildEntity($complexTableName,$dataset);
		}else{
			$ret = $dataset;
		}
		return $ret;
	}
	/**
	 * @param boolean $isOrmEnable
	 */
	public function setIsOrmEnable($isOrmEnable) {
		$this->isOrmEnable = $isOrmEnable;
	}
	/**
	 * @return the $tableName
	 */
	public function getTableName() {
		return $this->tableName;
	}


	
	
	
}

?>